import React, { PureComponent, Fragment } from 'react';
import { Button, Icon, Divider, Table, Modal, Spin, Alert, Popconfirm } from 'antd';
// import { connect } from 'dva';
import lodash from 'lodash';
import SyntaxHighlighter, { registerLanguage } from "react-syntax-highlighter/light";
import json from 'react-syntax-highlighter/languages/hljs/json';
import Xcode from 'react-syntax-highlighter/styles/hljs/xcode';
import ReactJson from 'react-json-view'
import jsonFormat from 'json-format';
// import PageHeaderLayout from '../../layouts/PageHeaderLayout';
import MetricConfigModalEditor from './MetricConfigModalEditor';
import ExpectValuesModalEditor from './ExpectValuesModalEditor';
import { testEsQuery, testMetricData } from '../../../services/alarm-job-controller';
import { CompareRuleMapper } from '../../../utils/enum';
// import classNames from 'classnames';
import styles from './MetricConfigAdd.less';

registerLanguage('json', json);

// @Form.create()
export default class MetricConfigAdd extends PureComponent {

  state = {
    // 显示查询ES结果
    showEsQuery: false,
    // 查询ES是否已结束
    esQueryLoading: false,
    // ES查询数据
    esQueryData: {
      method: '',
      path: '',
      body: '{}',
      restltData: {},
    },
    // 测试监控项数据-所有测试结果列表
    metricDataMatchesMap: {},

    // 是否显示新增或编辑监控项
    showMetricConfigModalEditor: false,
    // 监控项新增或编辑标识
    addFlagMetricConfigModalEditor: true,
    // 编辑或新增的“监控项”
    editEsMetricData: {
      metricTitle: undefined,
      method: "POST",
      path: undefined,
      body: undefined,
    },

    // 是否显示新增或编辑监控项
    showExpectValueModalEditor: false,
    // 监控项新增或编辑标识
    addFlagExpectValueModalEditor: true,
    // 编辑或新增的“预期响应结果”
    editExpectValueData: {
      metricTitle: undefined,
      title: undefined,
      key: undefined,
      compareRule: undefined,
      value: undefined,
    },
  }

  // 执行ES查询
  esQuery = ({ method, path, body }) => {
    this.setState({ showEsQuery: true, esQueryLoading: true, esQueryData: { method, path, body } });
    testEsQuery({ method, path, body }).then(res => this.setState({ esQueryLoading: false, esQueryData: { method, path, body, restltData: res } }))
      .catch(() => this.setState({ esQueryLoading: false, esQueryData: { method, path, body, restltData: { error: '查询ES错误' } } }));
  }

  // 执行监控项测试
  metricDataMatches = ({ metricTitle, method, path, body, expectValues }) => {
    const { metricDataMatchesMap } = this.state;
    let metricDataMatches = { ...metricDataMatchesMap[metricTitle], metricTitle, loading: true };
    metricDataMatchesMap[metricTitle] = metricDataMatches;
    this.setState({ metricDataMatchesMap: { ...metricDataMatchesMap } });
    testMetricData({ metricTitle, method, path, body, expectValues }).then(res => {
      metricDataMatches = { ...metricDataMatches, ...res };
      metricDataMatches.loading = false;
      // const { metricDataMatchesMap } = this.state;
      metricDataMatchesMap[metricTitle] = metricDataMatches;
      this.setState({ metricDataMatchesMap: { ...metricDataMatchesMap } });
    }).catch(() => {
      metricDataMatches.loading = false;
      metricDataMatches.querySuccess = false;
      metricDataMatches.failMessage = "查询ES失败";
      // const { metricDataMatchesMap } = this.state;
      metricDataMatchesMap[metricTitle] = metricDataMatches;
      this.setState({ metricDataMatchesMap: { ...metricDataMatchesMap } });
    });
  }

  // 显示单个监控项
  getEsMetricDataItem = ({ metricTitle, method, path, body, expectValues }) => {
    // if (expectValues.length <= 0) {
    //   expectValues.push({ title: '监控指标相等', key: 'hits.hits[0]._source.jdbcPoolingCount', value: 5, compareRule: 'equal' });
    //   expectValues.push({ title: '监控指标相等2', key: 'hits.hits[0]._source.jdbcPoolingCount', value: '5', compareRule: 'equal' });
    //   expectValues.push({ title: '监控指标相等3', key: 'hits.hits[0]._source.jdbcPoolingCount', value: '6', compareRule: 'equal' });
    // }
    const { delEsMetricDataFunc, delExpectValueFunc } = this.props;
    const { metricDataMatchesMap } = this.state;
    let metricDataMatches = metricDataMatchesMap[metricTitle];
    if (!metricDataMatches) {
      metricDataMatches = {
        metricTitle,
        loading: false,
        queryParams: undefined,
        querySuccess: undefined,
        failMessage: undefined,
        metricMap: undefined,
        expectValues: undefined,
      };
    }
    const expectValueArray = [];
    lodash.forEach(expectValues, (item, index) => {
      const expectValue = { ...item, index: index + 1 };
      // 匹配监控结果
      if (metricDataMatches.expectValues) {
        const matchesObject = lodash.find(metricDataMatches.expectValues, { title: item.title });
        if (matchesObject) {
          expectValue.matchesObject = matchesObject;
        }
      }
      expectValueArray.push(expectValue);
    });
    const columns = [
      { title: '#', dataIndex: 'index', width: 30 },
      { title: '标题', dataIndex: 'title', width: 100 },
      { title: '预期结果Key', dataIndex: 'key', width: 150 },
      { title: '预期结果值', dataIndex: 'value', width: 150 },
      {
        title: '比较规则', dataIndex: 'compareRule', key: "compareRule-1", width: 80, render: val => {
          let compareRule = CompareRuleMapper[val];
          if (!compareRule) compareRule = CompareRuleMapper.error;
          return <span title={compareRule.description}>{compareRule.label}</span>;
        },
      },
      {
        title: '测试匹配结果', dataIndex: 'matchesObject', width: 200, render: val => {
          if (!val) return <span style={{ color: '#faad14' }}>未测试</span>;
          if (metricDataMatches && metricDataMatches.querySuccess === false) return <span style={{ color: '#f5222d' }}>查询失败</span>;
          return (
            <span>
              <span style={{ color: val.matches ? '#52c41a' : '#f5222d', display: 'inline-block', width: 50, textAlign: 'center' }}>
                {val.matches ? '匹配' : '不匹配'}
              </span>
              {(val.value && val.metricValue) ? (
                <span style={{ marginLeft: 8 }}>{`${val.value}(预期值) -> ${val.metricValue}(实际值)`}</span>
              ) : ''}
              {(val.value && !val.metricValue) ? (
                <span style={{ marginLeft: 8 }}>{`${val.value}(预期值) -> null(实际值)`}</span>
              ) : ''}
              {(!val.value && val.metricValue) ? (
                <span style={{ marginLeft: 8 }}>{`${val.metricValue}(实际值)`}</span>
              ) : ''}
            </span>
          );
        },
      },
      {
        title: '操作', align: 'center', key: 'action', width: 80,
        render: (_, record) => (
          <Fragment>
            <a
              onClick={() => {
                this.setState({ editExpectValueData: { metricTitle, ...record }, addFlagExpectValueModalEditor: false, showExpectValueModalEditor: true });
                this.expectValuesModalEditorInit({ ...record });
              }}
            >
              编辑
            </a>
            <Divider type="vertical" />
            <Popconfirm
              placement="left"
              title="确定删除?"
              okText="删除"
              cancelText="取消"
              onConfirm={() => {
                if (delExpectValueFunc instanceof Function) {
                  delExpectValueFunc(metricTitle, record.title);
                }
              }}
            >
              <a>删除</a>
            </Popconfirm>
          </Fragment>
        ),
      },
    ];
    return (
      <div key={metricTitle} className={styles.divBox} style={{ position: 'relative' }}>
        <div className={styles.divBoxTitle}>监控项-[{metricTitle}]</div>
        <Spin delay={0} spinning={metricDataMatches.loading}>
          <Button.Group size="small" style={{ position: 'absolute', right: 12, top: 12 }}>
            <Button
              icon="caret-right"
              disabled={!expectValues || expectValues.length <= 0}
              onClick={() => this.metricDataMatches({ metricTitle, method, path, body, expectValues })}
            >
              测试
            </Button>
            <Button
              icon="edit"
              onClick={() => {
                this.metricConfigEditorInit(body);
                this.setState({ editEsMetricData: { metricTitle, method, path, body }, addFlagMetricConfigModalEditor: false, showMetricConfigModalEditor: true });
              }}
            >
              编辑
            </Button>
            <Popconfirm
              placement="leftTop"
              title="确定删除当前监控项?"
              okText="删除"
              cancelText="取消"
              onConfirm={() => {
                if (delEsMetricDataFunc instanceof Function) {
                  delEsMetricDataFunc(metricTitle);
                }
              }}
            >
              <Button icon="delete" type="danger">删除</Button>
            </Popconfirm>
          </Button.Group>
          <div style={{ marginLeft: 12 }}>
            <div style={{ marginTop: 8, marginBottom: 8 }}>
              <span style={{ fontSize: 15, fontWeight: 'bold' }}>监控数据查询条件：</span>
              <code className={styles.code}>{method}</code>
              <code className={styles.code}>{path}</code>
              <a style={{ marginLeft: 12 }} title="点击执行ES查询" onClick={() => this.esQuery({ method, path, body })}>
                <Icon type="search" theme="outlined" />
                <span style={{ marginLeft: 4 }}>查询</span>
              </a>
            </div>
            <div>
              <ReactJson src={JSON.parse(body)} name={false} iconStyle="circle" displayObjectSize={false} displayDataTypes={false} enableClipboard={false} collapsed={true} />
            </div>
          </div>
          {(metricDataMatches && metricDataMatches.querySuccess === false) ? (
            <Alert closable={false} type="error" message="查询失败" description={metricDataMatches.failMessage} />
          ) : ''}
          <Divider style={{ marginTop: 8, marginBottom: 8, fontSize: 14 }} orientation="left">预期响应结果</Divider>
          {
            (expectValueArray && expectValueArray.length > 0) ? (
              <Table
                size="small"
                bordered={false}
                rowKey={record => record.title}
                columns={columns}
                dataSource={expectValueArray}
                pagination={false}
              />
            ) : <Alert type="warning" showIcon message="当前监控项没有设置预期响应结果, 请添加" />
          }
          <Button
            style={{ width: '100%', marginTop: 8, marginBottom: 8 }}
            size="small"
            type="dashed"
            icon="plus"
            onClick={() => {
              this.setState({ editExpectValueData: { metricTitle, compareRule: 'equal' }, addFlagExpectValueModalEditor: true, showExpectValueModalEditor: true });
              this.expectValuesModalEditorInit({ compareRule: 'equal' });
            }}
          >
            新增预期响应结果
          </Button>
        </Spin>
      </div>
    );
  }

  getEsMetricDataList = (esMetricDataList) => {
    if (!esMetricDataList) return '';
    // if (esMetricDataList.length <= 0) {
    //   esMetricDataList.push({ metricTitle: '测试ES请求', method: 'POST', path: '/per-summary-*/_search', body: '{ "from": "0", "size": "1" }', expectValues: [] });
    //   esMetricDataList.push({ metricTitle: '测试ES请求2', method: 'POST', path: '/per-summary-*/_search', body: '{ "from": "0", "size": "1" }', expectValues: [] });
    // }
    return esMetricDataList.map(item => this.getEsMetricDataItem(item));
  }

  render() {
    const {
      showEsQuery,
      esQueryLoading,
      esQueryData,
      editEsMetricData,
      showMetricConfigModalEditor,
      addFlagMetricConfigModalEditor,
      editExpectValueData,
      addFlagExpectValueModalEditor,
      showExpectValueModalEditor,
    } = this.state;
    const { esMetricDataList, addEsMetricDataFunc, updateEsMetricDataFunc, addExpectValueFunc, updateExpectValueFunc } = this.props;
    return (
      <Fragment>
        {this.getEsMetricDataList(esMetricDataList)}
        <Button
          style={{ width: '100%', marginTop: 8, marginBottom: 8 }}
          size="large"
          type="dashed"
          icon="plus"
          onClick={() => this.setState({ editEsMetricData: { method: "POST" }, addFlagMetricConfigModalEditor: true, showMetricConfigModalEditor: true })}
        >
          新增监控项配置
        </Button>
        <Modal
          title="监控数据查询结果(ES查询)"
          footer={null}
          width="60%"
          style={{ top: 35 }}
          maskClosable={false}
          visible={showEsQuery}
          onCancel={() => this.setState({ showEsQuery: false })}
        >
          <Spin delay={100} spinning={esQueryLoading}>
            <SyntaxHighlighter customStyle={{ minHeight: 80, maxHeight: 350, marginTop: 0, border: "1px solid #d9d9d9" }} showLineNumbers language='json' style={Xcode}>
              {
                [
                  `-- 请求参数信息：`,
                  `${esQueryData.method} -> ${esQueryData.path}`,
                  `${jsonFormat(JSON.parse(esQueryData.body), { type: 'space', size: 2 })}`,
                ].join('\n')
              }
            </SyntaxHighlighter>
            <Divider style={{ marginTop: 8, marginBottom: 8, fontSize: 14 }}>查询结果</Divider>
            <div style={{ minHeight: 80, maxHeight: 380, overflowY: 'auto', border: "1px solid #d9d9d9" }}>
              <ReactJson
                src={esQueryData.restltData}
                name={false}
                iconStyle="circle"
                displayObjectSize={true}
                displayDataTypes={false}
                enableClipboard={true}
                collapsed={false}
              />
            </div>
          </Spin>
        </Modal>
        <MetricConfigModalEditor
          esMetricData={editEsMetricData}
          addFlag={addFlagMetricConfigModalEditor}
          metricTitleExists={metricTitle => lodash.findIndex(esMetricDataList, { metricTitle }) !== -1}
          resetFunc={reset => { this.metricConfigEditorReset = reset }}
          initFunc={init => { this.metricConfigEditorInit = init }}
          visible={showMetricConfigModalEditor}
          confirmLoading={false}
          onCancel={() => {
            this.setState({ showMetricConfigModalEditor: false });
            this.metricConfigEditorReset();
          }}
          onOk={data => {
            if (addFlagMetricConfigModalEditor === false) {
              if (updateEsMetricDataFunc instanceof Function) {
                updateEsMetricDataFunc(data);
              }
            } else if (addEsMetricDataFunc instanceof Function) {
              addEsMetricDataFunc(data);
            }
            this.setState({ showMetricConfigModalEditor: false });
            this.metricConfigEditorReset();
          }}
        />
        <ExpectValuesModalEditor
          expectValueData={editExpectValueData}
          addFlag={addFlagExpectValueModalEditor}
          titleExists={(metricTitle, title) => {
            const esMetricData = lodash.find(esMetricDataList, { metricTitle });
            if (esMetricData && esMetricData.expectValues) {
              return lodash.findIndex(esMetricData.expectValues, { title }) !== -1;
            }
            return false;
          }}
          resetFunc={reset => { this.expectValuesModalEditorReset = reset }}
          initFunc={init => { this.expectValuesModalEditorInit = init }}
          visible={showExpectValueModalEditor}
          confirmLoading={false}
          onCancel={() => {
            this.setState({ showExpectValueModalEditor: false });
            this.expectValuesModalEditorReset();
          }}
          onOk={({ metricTitle, title, key, compareRule, value }) => {
            if (addFlagExpectValueModalEditor === false) {
              if (updateExpectValueFunc instanceof Function) {
                updateExpectValueFunc(metricTitle, { title, key, compareRule, value });
              }
            } else if (addExpectValueFunc instanceof Function) {
              addExpectValueFunc(metricTitle, { title, key, compareRule, value });
            }
            this.setState({ showExpectValueModalEditor: false });
            this.expectValuesModalEditorReset();
          }}
        />
      </Fragment>
    );
  }
}
